import React from "react"
import * as ReactDOM from 'react-dom'
import Icon from "@/components/Icon/Icon";
import {Animate} from '@/lib/Animate'
import {observer} from "mobx-react/index";
import classNames from 'classnames'

function Message() {
    return _Message(Array.from(arguments), 'Message')
}

Message.TOP_LEFT = "top-left"
Message.TOP_RIGHT = "top-right"
Message.TOP_CENTER = "top-center"
Message.BOTTOM_LEFT = "bottom-left"
Message.BOTTOM_RIGHT = "bottom-right"
Message.BOTTOM_CENTER = "bottom-center"
Message.MIDDLE_CENTER = "middle-center"

const Animates = {
    [Message.TOP_LEFT]: 'move-left',
    [Message.TOP_RIGHT]: 'move-right',
    [Message.TOP_CENTER]: 'move-up',
    [Message.BOTTOM_LEFT]: 'move-left',
    [Message.BOTTOM_RIGHT]: 'move-right',
    [Message.BOTTOM_CENTER]: 'move-down',
    [Message.MIDDLE_CENTER]: 'move-up',
}

@observer
class MessageItem extends React.Component {

    static defaultProps = {
        closeable: true
    }

    close() {
        const {
            messageManager,
            animate,
            index
        } = this.props
        messageManager.clearMessage(index)
        animate.leaveAsync().then(() => {
            messageManager.removeContainer(index)
        })
    }

    render() {
        const {
            animate,
            icon,
            children,
            closeable
        } = this.props

        return (
            <div className={classNames('message-notice', animate.classNames)}
                 style={animate.styles}>
                {icon ? <Icon type={icon}/> : null}
                {children}
                {closeable ? <Icon type="close" onClick={this.close.bind(this)}/> : null}
            </div>)
    }
}

class MessageManager {
    rootContainers = {}
    messages = {}
    index = 0

    createMessage(props) {
        const {
            message,
            placement,
            icon,
            closeable
        } = props || {}
        this.index++
        const _placement = placement || Message.TOP_CENTER
        delete  props.placement
        const animate = new Animate(Animates[_placement])
        const container = this.createContainer(_placement, this.index, animate, props)
        ReactDOM.render(<MessageItem messageManager={this}
                                     animate={animate}
                                     index={this.index}
                                     closeable={closeable}
                                     icon={icon}> {message}</MessageItem>, container)
        animate.enter();
        ((index) => {
            this.removeContainerWithAnimate(index)
        })(this.index)
    }

    createRootContainer(placement) {
        const container = document.createElement('div');
        container.classList.add('message-notice-group')
        container.classList.add(placement)
        document.body.appendChild(container)
        this.rootContainers[placement] = container
        return container
    }

    createContainer(placement, index, animate, props) {
        const rootContainer = this.rootContainers[placement] || this.createRootContainer(placement)
        const container = document.createElement('div');
        container.classList.add('message-notice-wrapper')
        rootContainer.appendChild(container)
        this.messages[index] = {
            container,
            placement,
            animate,
            props
        }
        return container
    }

    removeContainerWithAnimate(index) {
        const message = this.messages[index]
        const {animate, props} = message
        message.timeoutId = setTimeout(() => {
            animate.leaveAsync().then(() => {
                this.removeContainer(index)
            })
        }, props.duration || 2000)
    }

    clearMessage(index) {
        const message = this.messages[index]
        if (message.timeoutId) {
            clearTimeout(message.timeoutId)
        }
    }

    removeContainer(index) {

        const message = this.messages[index]
        const {props, placement, container} = message
        props.onClose && props.onClose()
        const rootContainer = this.rootContainers[placement]
        if (rootContainer && container) {
            rootContainer.removeChild(container);
            ReactDOM.unmountComponentAtNode(container)
        }
    }
}

const messageManager = new MessageManager()

function _Message(params, method, icon) {
    if (params.length === 0) {
        throw new Error(`method ${method} missing paramter`)
    }

    if (typeof params[0] === "string") {
        return messageManager.createMessage({
            message: params[0],
            duration: params[1] || 2000,
            placement: params[2] || Message.TOP_CENTER,
            closeable: true,
            icon,
        })
    }

    return messageManager.createMessage(params[0])
}

Message.info = function () {
    return _Message(Array.from(arguments), 'Message.info', 'info')
}

Message.error = function () {
    return _Message(Array.from(arguments), 'Message.error', 'error')
}

Message.warn = function () {
    return _Message(Array.from(arguments), 'Message.warn', 'warn')
}

Message.success = function () {
    return _Message(Array.from(arguments), 'Message.success', 'check-circle')
}

export default Message

